//
//  string.hpp
//  utilities
//
//  Created by Sam Jaffe on 4/28/13.
//  Copyright (c) 2013 Sam Jaffe. All rights reserved.
//

#pragma once

#include <stdarg.h>
#include <stddef.h>
#include <stdio.h>

#ifdef __cplusplus
#include <string>
#include <vector>
#include <list>
#include <regex>

/**
 * Splits a string into parts based upon a delimiting factor, 
 * documentation is for each of the split(...) functions.
 *
 * _Tp: Implicitly 'std::basic_string<_CharT, _Traits, _Alloc>'
 * Delim: Either 'std::basic_string<_CharT, _Traits, _Alloc>', '_CharT', or '_CharT*'
 * container: A container type (i.e. std::vector<std::string>)
 *
 * @param string The string to be split
 * @param delim The delimiter
 * @param elems A container of pieces of the string
 * @param pos The starting point of the string to read from
 * @param end The ending point of the string to read from
 */
template <class Str, class Delim,
template <typename...> class container>
container<Str> &split(const Str& string, Delim delim,
                       container<Str>& elems,
                       typename Str::size_type pos,
                       typename Str::size_type end) {
    int next = 0;
    while((next = string.find(delim, pos)) != std::string::npos && next < end) {
        elems.insert(elems.end(), string.substr(pos, next));
        pos = next;
    }
    return elems;
}

template <class Str, template <typename...> class container>
container<Str> &split(const Str& string,
                       std::basic_regex<typename Str::value_type> delim,
                       container<Str>& elems,
                       typename Str::size_type pos,
                       typename Str::size_type end) {
    auto start = std::sregex_iterator{string.begin() + pos, string.begin() + end, delim};
    auto finish = std::sregex_iterator{};
    for (std::sregex_iterator it = start; it != finish; ++it) {
        std::smatch match = *it;
        std::string match_str = match.str();
        elems.insert(elems.end(), match_str);
    }
    return elems;
}

template <class Str, class Delim,
template <typename...> class container>
container<Str> &split(const Str& string, Delim delim, container<Str>& elems,
                       typename Str::size_type pos = 0) {
    return split(string, delim, elems, pos, string.size());
}

template <class Str, class Delim>
std::vector<Str> split(const Str& string, Delim delim,
                        typename Str::size_type pos,
                        typename Str::size_type end) {
    std::vector<Str> vec{};
    return split(string, delim, vec, pos, end);
}

template <class Str, class Delim>
std::vector<Str> split(const Str& string, Delim delim,
                        typename Str::size_type pos = 0) {
    std::vector<Str> vec{};
    return split(string, delim, vec, pos, string.size());
}

template<typename CharT, typename Traits, typename Alloc>
std::basic_string<CharT, Traits, Alloc> operator ^(
            const std::basic_string<CharT, Traits, Alloc>& lhs,
            const std::basic_string<CharT, Traits, Alloc>& rhs) {
    std::basic_string<CharT, Traits, Alloc> ret(lhs);
    for (int i = 0; i < std::min(lhs.size(), rhs.size()); i++) {
        ret[i] ^= rhs[i];
    }
    return ret;
}

extern "C" {
#endif
    
    char* asprintf(char * const fmt, ...) {
        va_list args;
        va_start(fmt, args);
        char* str = vasprintf(fmt, args);
        va_end(args);
        return str;
    }
    
    char* vasprintf(char * const fmt, va_list args) {
        size_t needed = vsnprintf(NULL, 0, fmt, args);
        char * output = (char*) malloc(needed * sizeof(char));
        vsnprintf(output, needed, fmt, args);
        return output;
    }
    
#ifdef __cplusplus
}
#endif

